﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Runtime.InteropServices;
using System.IO;

namespace PickGold.Util.Proxies
{
	/// <summary>
	/// 指示该程序集为接口实现程序集或类将实现的接口。
	/// </summary>
	[Serializable]
	[ComVisible(true)]
	[ClassInterface(ClassInterfaceType.None)]
	[ComDefaultInterface(typeof(_Attribute))]
	[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
	public class ImplementAttribute : Attribute
	{
		private string _Interface;
		[NonSerialized]
		private string _AssemblyName;

		/// <summary>
		/// 要实现的程序集的任意接口，以指示程序集，或类要实现的接口。
		/// </summary>
		/// <param name="type">接口程序集中的接口类型，或要实现的接口类型。</param>
		public ImplementAttribute(string type) : this(Type.GetType(type)) { }

		/// <summary>
		/// 要实现的程序集的任意接口，以指示程序集，或类要实现的接口。
		/// </summary>
		/// <param name="type">接口程序集中的接口类型，或要实现的接口类型。</param>
		public ImplementAttribute(Type type)
		{
			this._Interface = type.FullName;
			this._AssemblyName = type.Assembly.GetName().Name;
		}

		/// <summary>
		/// 要实现的接口。
		/// </summary>
		public string TypeName
		{
			get
			{
				return this._Interface;
			}
		}

		/// <summary>
		/// 要实现的程序集。
		/// </summary>
		public string AssemblyName
		{
			get
			{
				if (string.IsNullOrEmpty(this._AssemblyName))
					this._AssemblyName = Type.GetType(this._Interface).Assembly.GetName().Name;
				return this._AssemblyName;
			}
		}

		/// <summary>
		/// 优先级
		/// </summary>
		public int Priority { set; get; }

		/// <summary>
		/// 获取目标实现类型。
		/// </summary>
		/// <param name="type">要实现的类型。</param>
		/// <returns>实现类。</returns>
		public static Type GetImplementedType(Type type)
		{
			var priority = int.MinValue;
			var implement = type;
			var assemblies = AppDomain.CurrentDomain.GetAssemblies();
			var attributes = Reflector<object>.NullArray;
			foreach (var assembly in assemblies)
			{
				var custom = typeof(ImplementAttribute);
				try
				{
					attributes = assembly.GetCustomAttributes(custom, true);//查找实现属性。
				}
				catch (Exception x)//(FileLoadException x)//
				{
					Tracker.LastError = new Exception(assembly + " " + x.Message, x);
					throw Tracker.LastError;
					//Tracker.LastError = x;
					//attributes = assembly.GetCustomAttributes(true);//查找实现属性。
					//if (attributes != null)
					//    attributes = attributes.Where(item => item.GetType().FullName == custom.FullName).ToArray();
				}
				if (attributes == null || attributes.Length == 0)//如果该程序集未标明实现任何接口，则不处理。
					continue;

				var an = type.Assembly.GetName().Name;
				var ias = attributes as ImplementAttribute[];
				foreach (var ia in ias)
				{
					if (ia.AssemblyName == an)
					{
						ias = null;
						break;
					}
				}
				if (ias != null)//如果实现程序集与目标类程序集不符，则不处理。
					continue;

				var ts = assembly.GetTypes();
				foreach (var t in ts)
				{
					if (t.IsInterface || t.IsAbstract)//如果目标类型是接口或虚类型，则重来。
						continue;

					try
					{
						attributes = t.GetCustomAttributes(custom, true);//查找实现属性。
					}
					catch (Exception x)//(FileLoadException x)//
					{
						Tracker.LastError = new Exception(assembly + " " + x.Message, x);
						throw Tracker.LastError;
						//Tracker.LastError = x;
						//attributes = t.GetCustomAttributes(true);//查找实现属性。
						//if (attributes != null)
						//    attributes = attributes.Where(item => item.GetType().FullName == custom.FullName).ToArray();
					}
					if (attributes == null || attributes.Length == 0)//如果目标类未标识实现，则重来。
						continue;

					ias = attributes as ImplementAttribute[];
					var p = 0;
					foreach (var ia in ias)
					{
						if (ia.TypeName == type.FullName && ia.Priority >= priority)
						{
							//implement = t;
							//priority = ia.Priority;
							p = ia.Priority;
							ias = null;
							break;
						}
					}
					if (ias != null)
						continue;

					if (type.IsAssignableFrom(t))
					{
						implement = t;
						priority = p;
						//return t;
					}
				}
			}//foreach (var assembly in assemblies)

			if (implement == type)
				return null;

			return implement;
		}
	}
}
